#pragma once

#include <iostream>
#include <unistd.h>
#include <stdint.h>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/wait.h>
#include <pthread.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

const uint16_t defaultport = 8080;
const std::string defaultip = "0.0.0.0";

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};

class TcpServer;

struct ThreadData
{
    ThreadData(int fd, const std::string &clientip, const uint16_t &clientport, TcpServer *t)
        : _sockfd(fd), _clientip(clientip), _clientport(clientport), _tsvr(t)
    {
    }
    int _sockfd;
    std::string _clientip;
    uint16_t _clientport;
    TcpServer *_tsvr;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip)
        : _port(port), _ip(defaultip)
    {
    }
    // 初始化服务端
    void InitServer()
    {
        // 创建套接字
        // Tcp使用SOCK_STREAM
        // Udp使用SOCK_DGRAM
        _socket = socket(AF_INET, SOCK_STREAM, 0);
        if (_socket < 0)
        {
            tcplg(Fatal, "Create socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        tcplg(Info, "Create socket success, socket: %d", _socket);

        // setsockopt：防止偶发性的服务器无法进行立即重启
        int opt = 1;
        setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

        // 初始化tcp所用结构体sockaddr_in
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        // htons:将一个无符号短整型的主机字节序转换为网络字节序
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = inet_addr(_ip.c_str());

        // 将套接字和本地所设结构体sockaddr_in绑定
        if (bind(_socket, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            tcplg(Fatal, "bind socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        tcplg(Info, "bind socket success, socket: %d", _socket);

        // 监听套接字
        // Tcp面向连接，服务器是比较“被动的”，服务器一直处于等待连接到来的状态
        if (listen(_socket, 5) < 0)
        {
            tcplg(Fatal, "bind socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        tcplg(Info, "listen socket success, socket: %d", _socket);
    }
    // static void *Routine(void *args)
    // {
    //     // 设置为分离状态
    //     pthread_detach(pthread_self());
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->_tsvr->Service(td->_sockfd,td->_clientip,td->_clientport);//
    //     close(td->_sockfd);
    //     delete td;

    //     return nullptr;
    // }
    // 服务器开始运行
    void Start()
    {
        Daemon();
        
        ThreadPool<Task>::GetInstance()->Start();

        tcplg(Info, "TcpSever is running... ");
        while (true)
        {
            // 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            memset(&client, 0, sizeof(client));
            int acceptfd = accept(_socket, (struct sockaddr *)&client, &len);
            if (acceptfd < 0)
            {
                tcplg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            // ntohs:将一个16位无符号短整型数据从网络字节序转换为主机字节序
            uint16_t clientport = ntohs(client.sin_port);
            std::string clientip = inet_ntoa(client.sin_addr);

            tcplg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", acceptfd, clientip.c_str(), clientport);

            // 向接受请求的文件描述符中读取和写入数据

            // // 1. 单进程版本
            // Service(acceptfd,clientip,clientport);
            // close(acceptfd);

            // // 2. 多进程版本
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // childi
            //     // 子进程暂时不需要套接字，可关闭
            //     close(_socket);
            //     // 在子进程创建进程，创建结束则退出，便不会造成阻塞
            //     if(fork() > 0)
            //         exit(0);
            //     // 由孙子进程执行后续代码，system领养孙子进程
            //     Service(acceptfd,clientip,clientport);
            //     close(acceptfd);
            //     exit(0);
            // }
            // else if(id > 0)
            // {
            //     // 关闭该套接字，由子进程对其进行全权操作
            //     close(acceptfd);
            //     // 父进程
            //     pid_t rid = waitpid(id,nullptr,0);
            // }

            // // 3. 多线程版本
            // ThreadData *td = new ThreadData(acceptfd,clientip,clientport,this);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Routine,td);

            // 4. 线程池版本
            Task t(acceptfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }
    // // 读取和写入数据
    // void Service(const int sockfd,const std::string &clientip, const uint16_t &clientport)
    // {
    //     char buffer[DATASIZE];
    //     while (true)
    //     {
    //         // 接收数据
    //         ssize_t n = read(sockfd,buffer,sizeof(buffer));
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "client say# " << buffer << std::endl;

    //             // 向客户端响应数据
    //             std::string echo_string = "TcpServer echo# ";
    //             echo_string += buffer;
    //             write(sockfd,echo_string.c_str(),sizeof(echo_string));
    //         }
    //         else if(n == 0)
    //         {
    //             tcplg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport,sockfd);
    //             break;
    //         }
    //         else if(n==-1)
    //         {
    //             tcplg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d",sockfd,clientip.c_str(),clientport);
    //             perror("read fail");
    //             break;
    //         }
    //     }

    // }
    ~TcpServer()
    {
    }

private:
    int _socket;
    uint16_t _port;
    std::string _ip;
};